package org.nimi317.web_gis.service.impl;


import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import lombok.SneakyThrows;
import org.nimi317.web_gis.context.SecurityContextHolder;
import org.nimi317.web_gis.data.AreaCodeList;
import org.nimi317.web_gis.dao.AreaQualityMapper;
import org.nimi317.web_gis.dao.StationMapper;
import org.nimi317.web_gis.entity.AreaQuality;
import org.nimi317.web_gis.entity.Station;
import org.nimi317.web_gis.service.IAreaQualityService;
import org.nimi317.web_gis.service.IUpdateService;
import org.nimi317.web_gis.utils.TimeUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;
import java.util.stream.Collectors;

/**
 * <p>
 * 每个小时的区域质量 服务实现类
 * </p>
 *
 * @author nimi317
 * @since 2024-01-25
 */
@Service
@Transactional
public class AreaQualityServiceImpl extends ServiceImpl<AreaQualityMapper, AreaQuality> implements IAreaQualityService {

    private final AreaCodeList areaCodeList;

    private final StationMapper stationMapper;

    private final AreaQualityMapper areaQualityMapper;

    private final IUpdateService updateService;

    @Autowired
    private ThreadPoolTaskExecutor executor;

    public AreaQualityServiceImpl(AreaCodeList areaCodeList, StationMapper stationMapper, AreaQualityMapper areaQualityMapper, IUpdateService updateService) {
        this.areaCodeList = areaCodeList;
        this.stationMapper = stationMapper;
        this.areaQualityMapper = areaQualityMapper;
        this.updateService = updateService;
    }

    @SneakyThrows
    @Override
    public void updateAreaQualityData() {
        // 获取当前正在监测的站点
        LambdaQueryWrapper<Station> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Station::getStatus, true);
        List<Station> list = stationMapper.selectList(wrapper);

        // 进行分组，统计每个城市的数据
        Map<Integer, List<Station>> collect = list.stream().collect(Collectors.groupingBy(Station::getCityCode));
        CountDownLatch countDownLatch = new CountDownLatch(collect.size());
        LocalDateTime time = SecurityContextHolder.getLastTime();
        collect.forEach((item, stations) -> {
            executor.execute(() -> {
                try {
                    areaCodeList.updateArea(item, stations, time);
                } finally {
                    countDownLatch.countDown();
                }
            });
        });
        countDownLatch.await();
    }

    @Override
    public List<AreaQuality> getRecentAreaQuality(String id) {
        LambdaQueryWrapper<AreaQuality> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AreaQuality::getCityCode, id)
                .le(AreaQuality::getTimestamp, TimeUtils.getCurrentUsefulDateTime())
                .orderByDesc(AreaQuality::getTimestamp)
                .last("limit 24");
        return this.list(wrapper);
    }

    @Override
    public IPage<AreaQuality> getHistory(Integer integer, List<LocalDateTime> timeRange) {
        LambdaQueryWrapper<AreaQuality> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AreaQuality::getCityCode, integer)
                .ge(AreaQuality::getTimestamp, timeRange.get(0))
                .le(AreaQuality::getTimestamp, timeRange.get(1));
        return this.page(null, wrapper);
    }

    @Override
    public List<AreaQuality> getHistoryList(Integer integer, List<LocalDateTime> timeRange) {
        LambdaQueryWrapper<AreaQuality> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AreaQuality::getCityCode, integer)
                .ge(AreaQuality::getTimestamp, timeRange.get(0))
                .le(AreaQuality::getTimestamp, timeRange.get(1));
        return this.list(wrapper);
    }

    @Override
    public List<AreaQuality> getRealTime() {
        LocalDateTime lastUpdateTime = updateService.getLastUpdateTime();
        LambdaQueryWrapper<AreaQuality> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(AreaQuality::getTimestamp, lastUpdateTime);
        return this.list(wrapper);
    }

}
